﻿//TransactionFactory.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Plaza
{
	using System;

	using Ecng.Collections;

	using StockSharp.Algo;
	using StockSharp.BusinessEntities;
	using StockSharp.Plaza.Wrappers;

	internal static class Messages
	{
		public const string FutureRegister = "FutAddOrder";
		public const string FutureCancel = "FutDelOrder";
		public const string FutureCancelGroup = "FutDelUserOrders";
		public const string FutureReRegister = "FutMoveOrder";
		public const string FutureChangeLimit = "FutChangeClientProhibit";
		public const string FutureRegisterMultiLeg = "FutAddMultiLegOrder";
		public const string FutureChangeMoneyLimit = "FutChangeClientMoney";
		public const string FutureChangeBaseAssetLimit = "FutChangeClientVcb";
		public const string FutureChangeBfBaseAssetLimit = "FutChangeBrokerVcb";
		public const string FutureChangeBfMoneyLimit = "FutChangeBFMoney";
		public const string FutureChangeBfMoney = "FutChangeMoney";
		public const string FutureExchangeBfMoney = "FutExchangeBFMoney";

		public const string OptionRegister = "OptAddOrder";
		public const string OptionCancel = "OptDelOrder";
		public const string OptionCancelGroup = "OptDelUserOrders";
		public const string OptionReRegister = "OptMoveOrder";
		public const string OptionChangeLimit = "OptChangeClientProhibit";
		public const string OptionChangeExpiration = "OptChangeExpiration";
	}

	/// <summary>
	/// Фабрика транзакций.
	/// </summary>
	public class TransactionFactory
	{
		private static readonly PairSet<string, int> _messageIds = new PairSet<string, int>();

		private readonly PlazaConnectionPool _connectionPool;
		private readonly TransactionIdGenerator _idGenerator;

		internal const string MessagesCategory = "FORTS_MSG";
		internal const string MessagesFileName = "StockSharp.Plaza.Messages.ini";

		static TransactionFactory()
		{
			_messageIds.Add(Messages.FutureRegister, 36);
			_messageIds.Add(Messages.FutureCancel, 37);
			_messageIds.Add(Messages.FutureCancelGroup, 38);
			_messageIds.Add(Messages.FutureReRegister, 39);
			_messageIds.Add(Messages.FutureChangeLimit, 15);
			_messageIds.Add(Messages.FutureRegisterMultiLeg, 40);
			_messageIds.Add(Messages.FutureChangeMoneyLimit, 4);
			_messageIds.Add(Messages.FutureChangeBaseAssetLimit, 33);
			_messageIds.Add(Messages.FutureChangeBfBaseAssetLimit, 14);
			_messageIds.Add(Messages.FutureChangeBfMoneyLimit, 7);
			_messageIds.Add(Messages.FutureChangeBfMoney, 16);
			_messageIds.Add(Messages.FutureExchangeBfMoney, 1034);

			_messageIds.Add(Messages.OptionRegister, 41);
			_messageIds.Add(Messages.OptionCancel, 42);
			_messageIds.Add(Messages.OptionCancelGroup, 43);
			_messageIds.Add(Messages.OptionReRegister, 44);
			_messageIds.Add(Messages.OptionChangeLimit, 17);
			_messageIds.Add(Messages.OptionChangeExpiration, 12);
		}

		internal TransactionFactory(PlazaConnectionPool connectionPool, TransactionIdGenerator idGenerator)
		{
			if (connectionPool == null)
				throw new ArgumentNullException("connectionPool");

			if (idGenerator == null)
				throw new ArgumentNullException("idGenerator");

			_connectionPool = connectionPool;
			_idGenerator = idGenerator;
		}

		private IMessageFactoryWrapper _messageFactory;

		private IMessageFactoryWrapper MessageFactory
		{
			get
			{
				if (_messageFactory == null)
				{
					_messageFactory = WrapperHelper.CreateMessageFactory();
					_messageFactory.Init(MessagesFileName, "");
				}

				return _messageFactory;
			}
		}

		/// <summary>
		/// Создать транзакцию на регистрацию заявки.
		/// </summary>
		/// <param name="order">Заявка.</param>
		/// <returns>Транзакция регистрации заявки.</returns>
		public Transaction CreateRegister(Order order)
		{
			if (order == null)
				throw new ArgumentNullException("order");

			return CreateTransaction(order.Security.Type == SecurityTypes.Option ? Messages.OptionRegister : Messages.FutureRegister, order.TransactionId, order);
		}

		/// <summary>
		/// Создать транзакцию на снятие заявки.
		/// </summary>
		/// <param name="order">Заявка.</param>
		/// <returns>Транзакция снятия заявки.</returns>
		public Transaction CreateCancel(Order order)
		{
			if (order == null)
				throw new ArgumentNullException("order");

			return CreateTransaction(order.Security.Type == SecurityTypes.Option ? Messages.OptionCancel : Messages.FutureCancel, _idGenerator.GetNextId(), order);
		}

		/// <summary>
		/// Создать транзакцию на групповое снятие заявок.
		/// </summary>
		/// <param name="securityType">Тип инструмента.</param>
		/// <param name="orders">Заявки.</param>
		/// <returns>Транзакция группового снятия заявок.</returns>
		public Transaction CreateCancelGroup(SecurityTypes securityType, params Order[] orders)
		{
			return CreateTransaction(securityType == SecurityTypes.Option ? Messages.OptionCancelGroup : Messages.FutureCancelGroup, _idGenerator.GetNextId(), orders);
		}

		/// <summary>
		/// Создать транзакцию на перерегистрацию заявок.
		/// </summary>
		/// <param name="firstOrder">Первая заявка.</param>
		/// <param name="secondOrder">Вторая заявка.</param>
		/// <returns>Транзакцию на перерегистрацию заявок.</returns>
		public Transaction CreateReRegister(Order firstOrder, Order secondOrder)
		{
			if (firstOrder == null)
				throw new ArgumentNullException("firstOrder");

			if (secondOrder == null)
				throw new ArgumentNullException("secondOrder");

			return CreateTransaction(firstOrder.Security.Type == SecurityTypes.Option ? Messages.OptionReRegister : Messages.FutureReRegister, secondOrder.TransactionId, firstOrder, secondOrder);
		}

		/// <summary>
		/// Создать транзакцию на перерегистрацию пары заявок.
		/// </summary>
		/// <param name="firstOrder1">Первая удаляемая заявка.</param>
		/// <param name="secondOrder1">Первая новая заявка.</param>
		/// <param name="firstOrder2">Вторая удаляемая заявка.</param>
		/// <param name="secondOrder2">Вторая новая заявка.</param>
		/// <returns>Транзакцию на перерегистрацию пары заявок.</returns>
		public Transaction CreateReRegisterPair(Order firstOrder1, Order secondOrder1, Order firstOrder2, Order secondOrder2)
		{
			if (firstOrder1 == null)
				throw new ArgumentNullException("firstOrder1");

			if (secondOrder1 == null)
				throw new ArgumentNullException("secondOrder1");

			if (firstOrder2 == null)
				throw new ArgumentNullException("firstOrder2");

			if (secondOrder2 == null)
				throw new ArgumentNullException("secondOrder2");

			return CreateTransaction(firstOrder1.Security.Type == SecurityTypes.Option ? Messages.OptionReRegister : Messages.FutureReRegister,
					_idGenerator.GetNextId(), firstOrder1, secondOrder1, firstOrder2, secondOrder2);
		}

		/// <summary>
		/// Создать транзакцию на изменение денежных лимитов по клиентскому счету.
		/// </summary>
		/// <returns>Транзакцию на изменение денежных лимитов по клиентскому счету.</returns>
		public Transaction CreateChangeMoneyLimit()
		{
			return CreateTransaction(Messages.FutureChangeMoneyLimit, _idGenerator.GetNextId());
		}

		/// <summary>
		/// Создать транзакцию на изменение клиентских ограничений.
		/// </summary>
		/// <returns>Транзакцию на изменение клиентских ограничений.</returns>
		public Transaction CreateSetMoneyLimit()
		{
			return CreateTransaction(Messages.FutureChangeLimit, _idGenerator.GetNextId());
		}

		/// <summary>
		/// Создать транзакцию на экспирацию опциона.
		/// </summary>
		/// <returns>Транзакцию на экспирацию опциона.</returns>
		public Transaction CreateChangeExpiration()
		{
			return CreateTransaction(Messages.OptionChangeExpiration, _idGenerator.GetNextId());
		}

		/// <summary>
		/// Создать транзакцию на изменение клиентских параметров по базовому активу.
		/// </summary>
		/// <returns>Транзакцию на изменение клиентских параметров по базовому активу.</returns>
		public Transaction CreateChangeBaseAssetLimit()
		{
			return CreateTransaction(Messages.FutureChangeBaseAssetLimit, _idGenerator.GetNextId());
		}

		/// <summary>
		/// Создать транзакцию на 
		/// </summary>
		/// <param name="securityType">Тип инструмента.</param>
		/// <returns>Транзакцию на </returns>
		public Transaction CreateChangeLimit(SecurityTypes securityType)
		{
			return CreateTransaction(securityType == SecurityTypes.Option ? Messages.OptionChangeLimit : Messages.FutureChangeLimit, _idGenerator.GetNextId());
		}

		private Transaction CreateTransaction(string messageName, long transactionId, params Order[] orders)
		{
			var message = MessageFactory.CreateMessageByName(messageName);
			var transaction = new Transaction(message, messageName, transactionId, orders);

			transaction
				.SetAddress(_connectionPool.SrvAddress)
				.SetCategory(MessagesCategory)
				.SetMsgType(_messageIds[messageName]);

			return transaction;
		}
	}
}